//; ---------------------------------------------------------------------------
//; Object 1F - Crabmeat enemy (GHZ, SYZ)
//; ---------------------------------------------------------------------------

#include "crabmeat.h"

#include "../../sprite.h"
#include "../../objectsystemNEWER.h"

static object *obj;

//EXTERN DEFINITIONS HERE
extern word v_limitbtm2;

//; ---------------------------------------------------------------------------
//; Animation script - Crabmeat enemy
//; ---------------------------------------------------------------------------
byte _stand[3]        = { 0xF, 0, afEnd };
byte standslope[3]    = { 0xF, 2, afEnd };
byte standsloperev[3] = { 0xF, 0x22, afEnd };
byte _walk[5]         = { 0xF, 1, 0x21, 0, afEnd };
byte walkslope[5]     = { 0xF, 0x21, 3, 2, afEnd };
byte walksloperev[5]  = { 0xF, 1, 0x23, 0x22, afEnd };
byte _firing[3]       = { 0xF, 4, afEnd };
byte ball[4]          = { 1, 5, 6, afEnd };

byte *Ani_Crab[8]     = { _stand, standslope, standsloperev, _walk, walkslope, walksloperev, _firing, ball };

//; ---------------------------------------------------------------------------
//; Sprite mappings - Crabmeat enemy (GHZ, SYZ)
//; ---------------------------------------------------------------------------

byte stand_c[21] = {  4,
		 0xF0,  9, 0,	 0, 0xE8,   //; standing/middle walking frame
		 0xF0,  9, 8,	 0,    0,
		    0,	5, 0,    6, 0xF0,
		    0,	5, 8,    6,    0
};
byte walk_c[21] = {   4,
		 0xF0,  9, 0,  0xA, 0xE8,   //; walking
		 0xF0,  9, 0, 0x10,    0,
		    0,	5, 0, 0x16, 0xF0,
		    0,	9, 0, 0x1A,    0
};
byte slope1[21] = { 4,
		 0xEC,  9, 0,	 0, 0xE8,   //; walking on slope
		 0xEC,  9, 8,	 0,    0,
		 0xFC,  5, 8,	 6,    0,
		 0xFC,  6, 0, 0x20, 0xF0
};
byte slope2[21] = { 4,
		 0xEC,  9, 0,  0xA, 0xE8,   //; walking on slope
		 0xEC,  9, 0, 0x10,    0,
		 0xFC,  9, 0, 0x26,    0,
		 0xFC,  6, 0, 0x2C, 0xF0
};
byte firing[31] = { 6,
		 0xF0,  4, 0, 0x32, 0xF0,   //; firing projectiles
		 0xF0,  4, 8, 0x32,    0,
		 0xF8,  9, 0, 0x34, 0xE8,
		 0xF8,  9, 8, 0x34,    0,
		    8,	4, 0, 0x3A, 0xF0,
		    8,	4, 8, 0x3A,    0
};
byte ball1[6] = {    1,
		 0xF8,  5, 0, 0x3C, 0xF8 
};                                          //; projectile
byte ball2[6] = {    1,
		 0xF8,  5, 0, 0x40, 0xF8    //; projectile
};

byte *Map_Crab[7] = { stand_c, walk_c, slope1, slope2, firing, ball1, ball2 };

//==========

void (*Crab_Index[5])() = { Crab_Main, Crab_Action, Crab_Delete, Crab_BallMain, Crab_BallMove };


//OBJECT:					; XREF: Obj_Index
void Crabmeat(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Crab_Index(pc,d0.w),d1
    //jmp	Crab_Index(pc,d1.w)
    (*Crab_Index[routine])();
}

//; ===========================================================================

//Crab_Main:	; Routine 0
void Crab_Main()
{
    //move.b	#$10,obHeight(a0)
    obj->Height = 16;

    //move.b	#8,obWidth(a0)
    obj->Width = 8;

    //move.l	#Map_Crab,obMap(a0)
    obj->Map = Map_Crab;

    //move.w	#$400,obGfx(a0)
    obj->Gfx = 0x400;

    //move.b	#4,obRender(a0)
    obj->Render = 4;

    //move.b	#3,obPriority(a0)
    obj->Priority = 3;

    //move.b	#6,obColType(a0)
    obj->ColType = 6;

    //move.b	#$15,obActWid(a0)
    obj->ActionWidth = 0x15;

    //bsr.w	ObjectFall
    ObjectFall(obj);

    byte angle;
    //jsr	ObjFloorDist	; find floor
    signed short floorDist = ObjFloorDist(obj, angle);
  
    //tst.w	d1
    //bpl.s	@floornotfound
    if (floorDist < 0)
    {
        //add.w	d1,obY(a0)
        obj->Y = obj->Y + floorDist;

	//move.b	d3,obAngle(a0)
        obj->Angle = angle;

	//move.w	#0,obVelY(a0)
        obj->VelocityY = 0;

	//addq.b	#2,obRoutine(a0)
        obj->Routine = obj->Routine + 2;
    }
    
    //@floornotfound:
    //rts	
}

#define timedelay 0x30
#define crabmode 0x32

#define id_Crab_Main 0
#define id_Crab_Action 2
#define id_Crab_Delete 4
#define id_Crab_BallMain 6
#define id_Crab_BallMove 8

void (*index_c[2])() = { waittofire, walkonfloor };

//Crab_Action:	; Routine 2
void Crab_Action()
{
    //moveq	#0,d0
    //move.b	ob2ndRout(a0),d0
    byte secondRoutine = obj->secondRoutine;

    //move.w	@index(pc,d0.w),d1
    //jsr	@index(pc,d1.w)
    (*index_c[secondRoutine/2])();

    //lea	(Ani_Crab).l,a1
    byte **aniScript = Ani_Crab;

    //bsr.w	AnimateSprite
    AnimateSprite(obj, aniScript);

    //bra.w	RememberState
    RememberState(obj);
}


//@waittofire:				; XREF: @index
void waittofire()
{
    //subq.w	#1,timedelay(a0) ; subtract 1 from time delay
    ptrsubobjvariableword(timedelay, obj, 1);

    //bpl.s	@dontmove
    if ((signed short)ptrgetobjvariableword(timedelay, obj) < 0)
    {
        //tst.b	obRender(a0)
	//bpl.s	@movecrab
        if ((signed char)obj->Render < 0) 
        {
            byte oldstatus = obj->Status & 2;
	    //bchg	#1,crabmode(a0)
            ptrsetobjvariableword(crabmode, obj, (ptrgetobjvariableword(crabmode, obj)^2));

	    //bne.s	@fire
            if (oldstatus == 0)
            {
                movecrab();
            }
            else
                fire();
        }
        else { movecrab(); }
    }
    //@dontmove:
    //@noflip:
    //rts
}	

void movecrab()
{
    //@movecrab:
    //addq.b	#2,ob2ndRout(a0)
    obj->secondRoutine = obj->secondRoutine + 2;

    //move.w	#127,timedelay(a0) ; set time delay to approx 2 seconds
    ptrsetobjvariableword(timedelay, obj, 127);

    //move.w	#$80,obVelX(a0)	; move Crabmeat	to the right
    obj->VelocityX = 0x80;

    //bsr.w	Crab_SetAni 
    //addq.b	#3,d0
    byte anim = Crab_SetAni() + 3;

    //move.b	d0,obAnim(a0)
    obj->Anim = anim;

    byte oldstatus = obj->Status & 1;
    //bchg	#0,obStatus(a0)
    obj->Status = obj->Status ^ 1;

    //bne.s	@noflip
    if (oldstatus == 0) 
    {
        //neg.w	obVelX(a0)	; change direction
        obj->VelocityX = -obj->VelocityX;

        fire();
    }
}

void fire()
{
    //move.w	#59,timedelay(a0)
    ptrsetobjvariableword(timedelay, obj, 59);

    //move.b	#6,obAnim(a0)	; use firing animation
    obj->Anim = 6;
	
    //bsr.w	FindFreeObj
    object *fireballLeft = FindFreeObj();

    //bne.s	@failleft
    if (fireballLeft->ID == 0)
    {
        //move.b	#id_Crabmeat,0(a1) ; load left fireball
        fireballLeft->ID = id_Crabmeat;

	//move.b	#id_Crab_BallMain,obRoutine(a1)
        fireballLeft->Routine = id_Crab_BallMain;

	//move.w	obX(a0),obX(a1)
        fireballLeft->X = obj->X;

	//subi.w	#$10,obX(a1)
        fireballLeft->X = fireballLeft->X - 0x10;

	//move.w	obY(a0),obY(a1)
        fireballLeft->Y = obj->Y;

	//move.w	#-$100,obVelX(a1)
        fireballLeft->VelocityX = -0x100;
    }

    //bsr.w	FindFreeObj
    object *fireballRight = FindFreeObj();

    //bne.s	@failright
    if (fireballRight->ID == 0)
    {
        //move.b	#id_Crabmeat,0(a1) ; load right fireball
        fireballRight->ID = id_Crabmeat;

	//move.b	#id_Crab_BallMain,obRoutine(a1)
        fireballRight->Routine = id_Crab_BallMain;

	//move.w	obX(a0),obX(a1)
        fireballRight->X = obj->X;

	//addi.w	#$10,obX(a1)
        fireballRight->X = fireballRight->X + 0x10;

	//move.w	obY(a0),obY(a1)
        fireballRight->Y = obj->Y;

	//move.w	#$100,obVelX(a1)
        fireballRight->VelocityX = 0x100;
    }
   
    //@failright:
    //rts	
}   //; ===========================================================================

//@walkonfloor:				; XREF: @index
void walkonfloor()
{
    //subq.w	#1,timedelay(a0)
    ptrsubobjvariableword(timedelay, obj, 1);
   
    //bmi.s	loc_966E
    if ((signed short)ptrgetobjvariableword(timedelay, obj) >= 0)
    {
        //bsr.w	SpeedToPos
        SpeedToPos(obj);

	//bchg	#0,crabmode(a0)
        ptrsetobjvariableword(crabmode, obj, (ptrgetobjvariableword(crabmode, obj)^1));

	//bne.s	loc_9654
        if (ptrgetobjvariableword(crabmode, obj) == 0)
        {
	    //move.w	obX(a0),d3
            //addi.w	#$10,d3
            word crabX = obj->X + 16;
 
	    //btst	#0,obStatus(a0)
	    //beq.s	loc_9640
            if ((obj->Status & 1) != 0)
            {
		//subi.w	#$20,d3
                crabX = crabX - 32;
            }

            //loc_9640:
	    //jsr	ObjFloorDist2
            signed short floorDist = ObjFloorDist(obj, crabX);

	    //cmpi.w	#-8,d1
            //blt.s	loc_966E
	    //cmpi.w	#$C,d1
	    //bge.s	loc_966E
            if ((floorDist < -8) || (floorDist >= 0xC))
            {
                return;
            } 
	    //rts
        }	
        //; ===========================================================================
        else
        {
            //loc_9654:
            byte angle;
	    //jsr	ObjFloorDist
            signed short floorDist = ObjFloorDist(obj, angle);

	    //add.w	d1,obY(a0)
            obj->Y = obj->Y + floorDist;

	    //move.b	d3,obAngle(a0)
            obj->Angle = angle;

	    //bsr.w	Crab_SetAni
            //addq.b	#3,d0
            byte anim = Crab_SetAni() + 3;

	    //move.b	d0,obAnim(a0)
            obj->Anim = anim;
 
	    //rts
            return;
        }
    }

    //; ===========================================================================
    //loc_966E:
    //subq.b	#2,ob2ndRout(a0)
    obj->secondRoutine = obj->secondRoutine - 2;

    //move.w	#59,timedelay(a0)
    ptrsetobjvariableword(timedelay, obj, 59);
 
    //move.w	#0,obVelX(a0)
    obj->VelocityX = 0;

    //bsr.w	Crab_SetAni
    byte anim = Crab_SetAni();

    //move.b	d0,obAnim(a0)
    obj->Anim = anim;

    //rts
}	

//; ---------------------------------------------------------------------------
//; Subroutine to	set the	correct	animation for a	Crabmeat
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Crab_SetAni:				; XREF: loc_966E
long Crab_SetAni()
{
    //moveq	#0,d0
    long anim = 0;

    //move.b	obAngle(a0),d3
    signed char angle = obj->Angle;

    //bmi.s	loc_96A4
    if (angle >= 0)
    {
        
        //cmpi.b	#6,d3
        //bcs.s	locret_96A2
        if (angle >= 6)
        {
	    //moveq	#1,d0
            anim = 1;

	    //btst	#0,obStatus(a0)
            //bne.s	locret_96A2
            if ((obj->Status & 1) == 0)
            {
	        //moveq	#2,d0
                anim = 2;
            }
        }
    }
    //loc_96A4:
    //cmpi.b	#-6,d3
    //bhi.s	locret_96B6
    else if (angle < -6)
    {
        //moveq	#2,d0
        anim = 2;
		
        //btst	#0,obStatus(a0)
	//bne.s	locret_96B6
        if ((obj->Status & 1) == 0)
        {
 	    //moveq	#1,d0
            anim = 1;
        }
    }

    //locret_96B6:
    //	rts	
    //locret_96A2:
    //	rts	
    return anim;
}   //; End of function Crab_SetAni

//; ===========================================================================

//Crab_Delete:	; Routine 4
void Crab_Delete()
{
    //bsr.w	DeleteObject
    DeleteObject(obj);

}   //rts	

//; ===========================================================================
//; ---------------------------------------------------------------------------
//; Sub-object - missile that the	Crabmeat throws
//; ---------------------------------------------------------------------------

//Crab_BallMain:	; Routine 6
void Crab_BallMain()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //move.l	#Map_Crab,obMap(a0)
    obj->Map = Map_Crab;

    //move.w	#$400,obGfx(a0)
    obj->Gfx = 0x400;

    //move.b	#4,obRender(a0)
    obj->Render = 4;

    //move.b	#3,obPriority(a0)
    obj->Priority = 3;

    //move.b	#$87,obColType(a0)
    obj->ColType = 0x87;

    //move.b	#8,obActWid(a0)
    obj->ActionWidth = 8;

    //move.w	#-$400,obVelY(a0)
    obj->VelocityY = -0x400;

    //move.b	#7,obAnim(a0)
    obj->Anim = 7;
  
    Crab_BallMove();
}

//Crab_BallMove:	; Routine 8
void Crab_BallMove()
{
    //lea	(Ani_Crab).l,a1
    byte **aniScript = Ani_Crab;

    //bsr.w	AnimateSprite
    AnimateSprite(obj, aniScript);

    //bsr.w	ObjectFall
    ObjectFall(obj);

    //bsr.w	DisplaySprite
    DisplaySprite(obj);
 
    //move.w	(v_limitbtm2).w,d0
    //addi.w	#$E0,d0
    word bottombound = v_limitbtm2 + 0xE0;

    //cmp.w	obY(a0),d0	; has object moved below the level boundary?
    //bcs.s	@delete		; if yes, branch
    if (obj->Y > bottombound) 
    { 
        //@delete:
        //bra.w	DeleteObject 
        DeleteObject(obj); 
    }
	   
}//rts	

	
